package com.dxw.dao;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.*;
import com.dxw.utils.DbConn;
import com.dxw.utils.NumberUtils;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.*;

/**
 * 增删改查的基本操作
 */
public class BaseDao {

    /*创建一个查询对象*/
    private static QueryRunner queryRunner = new QueryRunner(DbConn.getDataSource());

    /**
     * 返回第一条数据--[实体类]
     */
    public <T> T queryObject(Connection conn, String sql, Class<T> cls,
                             Object...params)  {
        try {
            return queryRunner.query(conn, sql, new BeanHandler<>(cls), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回所有数据--[实体类]
     */
    public <T> List<T> queryObjects(Connection conn, String sql, Class<T> cls, Object...params){
        try {
            return queryRunner.query(conn, sql, new BeanListHandler<>(cls), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一条数据--[Object[](一条数据的所有值，没有字段)]
     */
    public Object[] queryArray(Connection conn, String sql, Object...params){
        try {
            return queryRunner.query(conn, sql, new ArrayHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回所有数据--[List<Object[]>(所有数据的所有值，没有字段)]
     */
    public List<Object[]> queryArrayList(Connection conn, String sql, Object...params){
        try {
            return queryRunner.query(conn, sql, new ArrayListHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一列数据的所有值--[List<Object>(默认第一列)]
     */
    public List<Object> queryColumnList(Connection conn,
                                        String sql, Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new ColumnListHandler<>(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一列数据的所有值--[List<Object>(根据传递的索引列数，从1开始)]
     */
    public List<Object> queryColumnList(Connection conn,
                                        String sql,
                                        int columnIndex,
                                        Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new ColumnListHandler<>(columnIndex),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一列数据的所有值--[List<Object>(根据传递的列字段名)]
     */
    public List<Object> queryColumnList(Connection conn,
                                        String sql,
                                        String columnName,
                                        Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new ColumnListHandler<>(columnName),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将每一行数据都封装到一个Map里，
     * 然后再根据指定的key把每个Map再存放到一个大的Map里。
     * 外面指定的key不能重复。--[Map<Object, Map<String, Object>>默认第一列]
     */
    public Map<Object, Map<String, Object>> queryKeyed(Connection conn,
                                                       String sql,
                                                       Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new KeyedHandler<>(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将每一行数据都封装到一个Map里，
     * 然后再根据指定的key把每个Map再存放到一个大的Map里。
     * 外面指定的key不能重复。--[Map<Object, Map<String, Object>>根据传递的索引列数，从1开始]
     */
    public Map<Object, Map<String, Object>> queryKeyed(Connection conn,
                                                       String sql,
                                                       int columnIndex,
                                                       Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new KeyedHandler<>(columnIndex),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将每一行数据都封装到一个Map里，
     * 然后再根据指定的key把每个Map再存放到一个大的Map里。
     * 外面指定的key不能重复。--[Map<Object, Map<String, Object>>(根据传递的列字段名)]
     */
    public Map<Object, Map<String, Object>> queryKeyed(Connection conn,
                                                       String sql,
                                                       String columnName,
                                                       Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new KeyedHandler<>(columnName),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一条数据--[Map<String, Object>(将字段名和值存在一个map集合中)]
     */
    public Map<String, Object> queryMap(Connection conn, String sql, Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new MapHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回多条数据--[List<Map<String, Object>>]
     */
    public List<Map<String, Object>> queryMaps(Connection conn, String sql, Object...params){
        try {
            return queryRunner.query(conn, sql,
                    new MapListHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一行的某一列值--[默认第一列]
     * @return 查询的那一列的值类型
     */
    public Object queryScalar(Connection conn,
                              String sql,
                              Object ... params){
        try {
            return queryRunner.query(conn, sql,
                    new ScalarHandler<>(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一行的某一列值--[根据传递的索引，从1开始]
     */
    public Object queryScalar(Connection conn,
                              String sql,
                              int columnIndex,
                              Object[] params){
        try {
            return queryRunner.query(conn, sql,
                    new ScalarHandler<>(columnIndex),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一行的某一列值--[根据传递的列字段名]
     */
    public Object queryScalar(Connection conn,
                              String sql,
                              String columnName,
                              Object[] params){
        try {
            return queryRunner.query(conn, sql,
                    new ScalarHandler<>(columnName),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 返回第一行的某一列值--[默认第一列]
     */
    public Long queryScalarForLong(Connection conn,
                              String sql,
                              Object ... params){
        return Long.parseLong(queryScalar(conn, sql, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的索引，从1开始]
     */
    public Long queryScalarForLong(Connection conn,
                              String sql,
                              int columnIndex,
                              Object[] params){
        return Long.parseLong(queryScalar(conn, sql, columnIndex, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的列字段名]
     */
    public Long queryScalarForLong(Connection conn,
                              String sql,
                              String columnName,
                              Object[] params){
        return Long.parseLong(queryScalar(conn, sql, columnName, params).toString());
    }

    /**
     * 返回第一行的某一列值--[默认第一列]
     */
    public Integer queryScalarForInteger(Connection conn,
                                   String sql,
                                   Object ... params){
        return NumberUtils.parseInt(queryScalar(conn, sql, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的索引，从1开始]
     */
    public Integer queryScalarForInteger(Connection conn,
                                   String sql,
                                   int columnIndex,
                                   Object[] params){
        return NumberUtils.parseInt(queryScalar(conn, sql, columnIndex, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的列字段名]
     */
    public Integer queryScalarForInteger(Connection conn,
                                   String sql,
                                   String columnName,
                                   Object[] params){
        return NumberUtils.parseInt(queryScalar(conn, sql, columnName, params).toString());
    }

    /**
     * 更新--[包括增删改]
     */
    public int update(Connection conn, String sql, Object...params){
        try {
            return queryRunner.update(conn, sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 批量更新--[只有更新才有批量操作]
     */
    public int[] batch(Connection conn, String sql, Object[][] params){
        try {
            return queryRunner.batch(conn, sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 返回第一条数据--[实体类]
     */
    public <T> T queryObject(String sql, Class<T> cls, Object...params){
        try {
            return queryRunner.query(sql, new BeanHandler<>(cls), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回多条数据--[实体类]
     */
    public <T> List<T> queryObjects(String sql, Class<T> cls, Object...params){
        try {
            return queryRunner.query(sql, new BeanListHandler<>(cls), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一条数据--[Object[](一条数据的所有值，没有字段)]
     */
    public Object[] queryArray(String sql, Object...params){
        try {
            return queryRunner.query(sql, new ArrayHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回所有数据--[List<Object[]>(所有数据的所有值，没有字段)]
     */
    public List<Object[]> queryArrayList(String sql, Object...params){
        try {
            return queryRunner.query(sql, new ArrayListHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一列数据的所有值--[List<Object>(默认第一列)]
     */
    public List<Object> queryColumnList(String sql, Object...params){
        try {
            return queryRunner.query(sql,
                    new ColumnListHandler<>(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一列数据的所有值--[List<Object>(根据传递的索引列数，从1开始)]
     */
    public List<Object> queryColumnList(String sql,
                                        int columnIndex,
                                        Object...params){
        try {
            return queryRunner.query(sql,
                    new ColumnListHandler<>(columnIndex),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一列数据的所有值--[List<Object>(根据传递的列字段名)]
     */
    public List<Object> queryColumnList(String sql,
                                        String columnName,
                                        Object...params){
        try {
            return queryRunner.query(sql,
                    new ColumnListHandler<>(columnName),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将每一行数据都封装到一个Map里，
     * 然后再根据指定的key把每个Map再存放到一个大的Map里。
     * 外面指定的key不能重复。--[Map<Object, Map<String, Object>>默认第一列]
     */
    public Map<Object, Map<String, Object>> queryKeyed(String sql,
                                                       Object...params){
        try {
            return queryRunner.query(sql,
                    new KeyedHandler<>(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将每一行数据都封装到一个Map里，
     * 然后再根据指定的key把每个Map再存放到一个大的Map里。
     * 外面指定的key不能重复。--[Map<Object, Map<String, Object>>根据传递的索引列数，从1开始]
     */
    public Map<Object, Map<String, Object>> queryKeyed(String sql,
                                                       int columnIndex,
                                                       Object...params){
        try {
            return queryRunner.query(sql,
                    new KeyedHandler<>(columnIndex),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 将每一行数据都封装到一个Map里，
     * 然后再根据指定的key把每个Map再存放到一个大的Map里。
     * 外面指定的key不能重复。--[Map<Object, Map<String, Object>>(根据传递的列字段名)]
     */
    public Map<Object, Map<String, Object>> queryKeyed(String sql,
                                                       String columnName,
                                                       Object...params){
        try {
            return queryRunner.query(sql,
                    new KeyedHandler<>(columnName),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回一条数据--[Map<String, Object>(将字段名和值存在一个map集合中)]
     */
    public Map<String, Object> queryMap(String sql, Object...params){
        try {
            return queryRunner.query(sql,
                    new MapHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回多条数据--[List<Map<String, Object>>]
     */
    public List<Map<String, Object>> queryMaps(String sql, Object...params){
        try {
            return queryRunner.query(sql,
                    new MapListHandler(),
                    params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一行的某一列值--[默认第一列]
     */
    public Object queryScalar(String sql, Object ... params){
        try {
            return queryRunner.query(sql, new ScalarHandler<>(), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一行的某一列值--[根据传递的索引，从1开始]
     */
    public Object queryScalar(String sql, int columnIndex, Object[] params){
        try {
            return queryRunner.query(sql, new ScalarHandler<>(columnIndex), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 返回第一行的某一列值--[根据传递的列字段名]
     */
    public Object queryScalar(String sql, String columnName, Object[] params){
        try {
            return queryRunner.query(sql,new ScalarHandler<>(columnName), params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }


    /**
     * 返回第一行的某一列值--[默认第一列]
     */
    public Long queryScalarForLong(String sql, Object ... params){
        return Long.parseLong(queryScalar(sql, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的索引，从1开始]
     */
    public Long queryScalarForLong(String sql, int columnIndex, Object[] params){
        return Long.parseLong(queryScalar(sql, columnIndex, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的列字段名]
     */
    public Long queryScalarForLong(String sql, String columnName, Object[] params){
        return Long.parseLong(queryScalar(sql, columnName, params).toString());
    }

    /**
     * 返回第一行的某一列值--[默认第一列]
     */
    public Integer queryScalarForInteger(String sql, Object ... params){
        return NumberUtils.parseInt(queryScalar(sql, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的索引，从1开始]
     */
    public Integer queryScalarForInteger(String sql, int columnIndex, Object[] params){
        return NumberUtils.parseInt(queryScalar(sql, columnIndex, params).toString());
    }

    /**
     * 返回第一行的某一列值--[根据传递的列字段名]
     */
    public Integer queryScalarForInteger(String sql, String columnName, Object[] params){
        return NumberUtils.parseInt(queryScalar(sql, columnName, params).toString());
    }

    /**
     * 更新--[包括增删改]
     */
    public int update(String sql, Object...params){
        try {
            return queryRunner.update(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return 0;
    }

    /**
     * 批量更新--[只有更新才有批量操作]
     */
    public int[] batch(String sql, Object[][] params){
        try {
            return queryRunner.batch(sql, params);
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return null;
    }

    //-------------------------------常用方法------------------------------
    /**
     * 通过实体类对象，获取与实体类相关联的插入语句
     * <br>
     *     注意：实体类字段与数据库【列名】与【列数量】必须一致
     */
    public String getSQL(Map<String, Object> SQLandParamsMap){
        return (String) SQLandParamsMap.get("sql");
    }

    /**
     * 通过实体类对象，获取与实体类相关联的参数
     */
    public Object[] getParams(Map<String, Object> SQLandParamsMap){
        return (Object[]) SQLandParamsMap.get("params");
    }

    /**
     * 获取插入sql语句与参数数组
     * @param obj 需要转化的实体类对象
     */
    public Map<String, Object> insertSQLandParams(Object obj){
        Map<String, Object> SQLandParamsMap = new HashMap<>();
        //0.获取这个对象的反射
        Class cls = obj.getClass();
        //1.创建字符串生成器
        StringBuilder sqlStr = new StringBuilder();
        sqlStr.append("insert into ").append(cls.getSimpleName()).append("(");
        //将实体类对象中不为空的值转化为json对象
        JSONObject objJson = (JSONObject) JSON.toJSON(obj);

        //创建一个新的字符串生成，专门拼接占位符
        StringBuilder placeholderStr = new StringBuilder();
        placeholderStr.append(" values(");
        //创建一个参数列表。参数的数量和字段的数量是一样的
        //获取所有的键值对
        Set<Map.Entry<String, Object>> fieldsSet = objJson.entrySet();
        //创建参数
        List<Object> paramsList = new ArrayList<>();
        //循环遍历所有的key
        for (Map.Entry<String, Object> entry : fieldsSet) {
            sqlStr.append(entry.getKey()).append(",");
            placeholderStr.append("?,");
            //执行get方法取出值并放入到params数组
            paramsList.add(entry.getValue());
        }
        //3.去掉最后一个逗号
        sqlStr.setLength(sqlStr.length()-1);
        sqlStr.append(")");
        placeholderStr.setLength(placeholderStr.length()-1);
        placeholderStr.append(")");
        //将占位符贫瘠额到主sql
        sqlStr.append(placeholderStr);
        //将两个对象存储到map集合中
        SQLandParamsMap.put("sql", sqlStr.toString());
        SQLandParamsMap.put("params", paramsList.toArray());
        return SQLandParamsMap;
    }

    /**
     * 直接保存一个对象
     */
    public boolean saveObject(Object obj){
        //获取sql和参数，并设置进去
        Map<String, Object> map = insertSQLandParams(obj);
        return update(getSQL(map), getParams(map)) > 0;
    }

    /**
     * 自动生成update语句
     * @param obj 实体类对象
     */
    public Map<String, Object> updateSQLandParams(Object obj) {
        //创建字符串生成器，主更新sql
        StringBuilder sqlStr = new StringBuilder();
        //通过对象获取反射
        Class cls = obj.getClass();
        sqlStr.append("update ").append(cls.getSimpleName()).append(" set ");
        //将实体类对象中不为空的值转化为json对象
        JSONObject objJson = (JSONObject) JSON.toJSON(obj);
        //获取所有的键值对
        Set<Map.Entry<String, Object>> fieldsSet = objJson.entrySet();
        //创建参数
        List<Object> paramsList = new ArrayList<>();
        //循环遍历所有的key
        for (Map.Entry<String, Object> entry : fieldsSet) {
            sqlStr.append(entry.getKey()).append("=?,");
            //执行get方法取出值并放入到params数组
            paramsList.add(entry.getValue());
        }
        //sql去掉最后一个逗号
        sqlStr.setLength(sqlStr.length()-1);
        //拼接where的参数
        sqlStr.append(" where id = ?");
        //获取id的值
        paramsList.add(objJson.get("id"));
        //加入map集合中
        Map<String, Object> map = new HashMap<>();
        map.put("sql", sqlStr.toString());
        map.put("params", paramsList.toArray());
        return map;
    }

    /**
     * 根据id直接更新一个对象
     */
    public boolean updateObject(Object obj){
        Map<String, Object> map = updateSQLandParams(obj);
        return update(getSQL(map), getParams(map)) > 0;
    }



    public static void main(String[] args) {

    }

}
